//
//  DemoCodable.swift
//  swiftDemo
//
//  Created by JIENING ZHANG on 2020/10/29.
//  Copyright © 2020 lovivid. All rights reserved.
//

import UIKit

/*
 https://www.jianshu.com/p/4876e94862e2
 
 NSCoding
    这个协议在Cocoa的Foundation框架中定义，内置的大多数Cocoa类都采用了NSCoding协议，比如 UIColor 等。
    采用了这个协议的对象可以转换为 NSData 类型，然后再转换回来。使用 NSKeyedArchiver 和 NSKeyedUnarchiver 分别进行归档和解档。
    采用这个协议的对象需要实现 encode(with:) 进行归档，以及 init(coder:) 进行解档。
    在 iOS12中，苹果推荐使用 NSSecureCoding 协议，这个协议在NSCoding的基础上，还需要实现一个静态的 supportsSecureCoding 属性
        static var supportsSecureCoding: Bool {return true}


 Codable
    这个是swift4.0中引入的新协议，主要是为了解决数据（比如JSON）序列化问题。它实际上是 Encodable 和 Decodable 协议的结合.
    使用Codable的对象，类实例，结构体实例，枚举实例（RawRepresentable 类型的枚举，即拥有 raw value）等都可以被编码
    任何对象只要遵守Encodable协议，都可以被序列化（归档），任何遵循Decodable协议的对象都可以从序列化形式恢复（解档）。

    存在3种形式的序列化模式：
        property list:  使用 PropertyListEncoder 的 encode(_:) 进行编码，使用 PropertyListDecoder 的 decode(_:from:) 进行解码
        JSON:           使用 JSONEncoder 的 encode(_:) 进行编码，使用 JSONDecoder 的 decode(_:from:) 进行解码
        NSCoder:        使用 NSKeyedArchiverEncoder 的 encodeEncodable(_:forKey:) 进行编码，使用 NSKeyedUnarchiverDecoder 的 decodeDecodable(_:forKey:) 进行解码
     
    大多数内置的Swift类型都是默认的Codable，encode(to:) 和 init(from:) 类似于 NSCoding中的 encode(with:) 和 init(coder:), 但是通常不需要我们去实现，因为通过扩展协议的方式，提供了默认的实现

 */

class DemoCodable: NSObject,Codable {
    var name:String = ""
    var cDate:Date = Date()
    var binData:Data? = nil
    var info:Dictionary<String, String> = [:]
    var children:Array<DemoCodable> = []
    
    enum DemoCodingKeys : String, CodingKey {
        case name       = "tName"
        case cDate      = "tDate"
        case binData    = "tBin"
        case info       = "tDic"
        case children   = "tArray"
      }
    
    func encode(to encoder:Encoder) throws {
        var container = encoder.container(keyedBy: DemoCodingKeys.self)

        try container.encode(name,      forKey: .name)
        try container.encode(cDate,     forKey: .cDate)

        try container.encodeIfPresent(binData,   forKey: .binData)
        
        try container.encode(info,      forKey: .info)
        try container.encode(children,  forKey: .children)
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DemoCodingKeys.self)

        name        = try container.decode(String.self,     forKey: .name)
        cDate       = try container.decode(Date.self,       forKey: .cDate)
        
        binData     = try container.decodeIfPresent(Data.self,       forKey: .binData)
        
        info        = try container.decode(Dictionary<String, String>.self, forKey: .info)
        children    = try container.decode(Array<DemoCodable>.self,      forKey: .children)
    }
    
    override init() {
        super.init()
    }
    
    override var description : String {
        "name : \(name), cDate : \(cDate),  binData:\(binData), info:\(info), children:\(children)"
    }
}
